量化交易30天
本系列文章是紀錄一位量化交易新手的學習過程,除了基礎的Python語法不說明,其他金融相關的東西都會一步步地說明,希望讓更多想學習量化交易但是沒有學過相關金融知識的朋友們,透過這系列的文章,能夠對量化交易略知一二,也歡迎量化交易的高手們多多交流。
上一篇是指定用14天計算RSI,並且用RSI14大於80賣出,小於30買進,最後在2019年得到15.72%的報酬率,不過這些參數其實都是可以調整的,這篇就來試試看調整這些參數,看看能不能得到比較好的報酬率。
由於要做最佳化參數的話,需要把可以調整的參數都放到函數裡面,才能用迴圈去暴力求最佳解,因此下面就先把需要的函數列出來。
# RSI函數
def RSI(Close, period=12):
# 整理資料
import pandas as pd
Chg = Close - Close.shift(1)
Chg_pos = pd.Series(index=Chg.index, data=Chg[Chg>0])
Chg_pos = Chg_pos.fillna(0)
Chg_neg = pd.Series(index=Chg.index, data=-Chg[Chg<0])
Chg_neg = Chg_neg.fillna(0)
# 計算12日平均漲跌幅度
import numpy as np
up_mean = []
down_mean = []
for i in range(period+1, len(Chg_pos)+1):
up_mean.append(np.mean(Chg_pos.values[i-period:i]))
down_mean.append(np.mean(Chg_neg.values[i-period:i]))
# 計算 RSI
rsi = []
for i in range(len(up_mean)):
rsi.append( 100 * up_mean[i] / ( up_mean[i] + down_mean[i] ) )
rsi_series = pd.Series(index = Close.index[period:], data = rsi)
return rsi_series
# RSI策略函數
def RSI_Trading_Sig(RSI, upper = 80, lower = 20):
import pandas as pd
# 訊號標籤
sig = []
# 庫存標籤,只會是0或1,表示每次交易都是買進或賣出所有部位
stock = 0
# 偵測RSI訊號
for i in range(len(RSI)):
if RSI[i] > upper and stock == 1:
stock -= 1
sig.append(-1)
elif RSI[i] < lower and stock == 0:
stock += 1
sig.append(1)
else:
sig.append(0)
# 將格式轉成 time series
rsi_sig = pd.Series(index = RSI.index, data = sig)
return rsi_sig
def RSI_backtest(RSI_Trading_Sig, Open_Price):
# 每次買賣的報酬率
rets = []
# 是否仍有庫存
stock = 0
# 當次交易買入價格
buy_price = 0
# 當次交易賣出價格
sell_price = 0
# 每次買賣的報酬率
for i in range(len(RSI_Trading_Sig)-1):
if RSI_Trading_Sig[i] == 1:
# 隔日開盤買入
buy_price = Open_Price[RSI_Trading_Sig.index[i+1]]
stock += 1
elif RSI_Trading_Sig[i] == -1:
# 隔日開盤賣出
sell_price = Open_Price[RSI_Trading_Sig.index[i+1]]
stock -= 1
rets.append((sell_price-buy_price)/buy_price)
buy_price = 0
sell_price = 0
# 如果最後手上有庫存,就用回測區間最後一天的開盤價賣掉
if stock == 1 and buy_price != 0 and sell_price == 0:
sell_price = Open_Price[-1]
rets.append((sell_price-buy_price)/buy_price)
# 總報酬率
total_ret = 1
for ret in rets:
total_ret *= 1 + ret
return total_ret
有了上面這三個函數之後,就可以使用暴力法來求最佳解:
# 串接API取資料
import os
import pandas_datareader as pdr
SPY = pdr.get_data_tiingo('SPY', api_key='6af47abd76fbc371d5606fca0694502b866c7bcf')
SPY = SPY.reset_index(level=[0,1])
SPY.index = SPY['date']
SPY_adj = SPY.iloc[:,7:12]
SPY_adj.columns = ['Close','High','Low','Open','Volume']
# 篩選2019年開收盤價資料
Close2019 = SPY_adj.Close['2019']
Open2019 = SPY_adj.Open['2019']
# 參數最佳化 No1,所有參數皆可調整
max_total_ret, max_period, max_upper, max_lower = 0, 0, 0, 0
for period in range(6,25):
for upper in range(70,91):
for lower in range(10,31):
ret = RSI_backtest(RSI_Trading_Sig(RSI(Close2019, period), upper, lower), Open2019)
if ret > max_total_ret:
max_total_ret, max_period, max_upper, max_lower = ret, period, upper, lower
# 將求出來的結果印出參數及圖看看
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from matplotlib import gridspec
x = RSI(Close2019, max_period).index
y = RSI(Close2019, max_period).values
fig = plt.figure(figsize=(15,10))
# set height ratios for sublots
gs = gridspec.GridSpec(2, 1, height_ratios=[2, 1])
# the fisrt subplot
ax0 = plt.subplot(gs[0])
# line0 = ax0.plot(x, y, color='r')
ax0.plot(RSI(Close2019, max_period))
ax0.axhline(y=max_upper, color='red')
ax0.axhline(y=max_lower, color='green')
#the second subplot
# shared axis X
ax1 = plt.subplot(gs[1], sharex = ax0)
rsi_sig = pd.Series(index = RSI(Close2019, max_period).index, data = list(RSI_Trading_Sig(RSI(Close2019, max_period), max_upper, max_lower).values))
ax1.plot(rsi_sig)
print('總報酬率:' + str(round(100*(max_total_ret-1),2)) + '%')
print('參數:' + 'RSI計算天數: ' + str(period) + ' ,Upper bond: ' + str(max_upper) + ' ,Lower bond: ' + str(max_lower))
plt.show()
總報酬率:24.62%
參數:RSI計算天數: 24 ,Upper bond: 90 ,Lower bond: 24
本篇總結
從這個圖可以看得出來,最佳化的過程中,會盡量讓Upper bond與Lower bond拉到最開,然後交易次數也需要兼顧到。對於這個最佳化的過程,有幾個觀念是可以注意的:
P.S.
如果大家對於量化交易有興趣的話,我自己有上過以下這門課,課程內容從串接股市資料API、儲存至資料庫、將自己的策略轉化成程式碼、自動下單,並且可以把整個流程自動化,每天早上執行一次,一整天就不用看盤了,覺得是蠻實戰的,可以參考看看。
筆者 Sean
奈米戶投資人 / Python愛用者
喜歡用Python玩轉金融數據,從個股基本面、技術面、籌碼面相關資料,一直到總體經濟數據,都是平常接觸到的素材;對於投資,除了研究歷史數據,也喜歡瞭解市場上大家在玩些什麼。